#include "main.h"

bool is_operator(char symbol) {
    char operator[7] = { '+','-','*','/','(',')','#' };
    for (int i = 0; i < 7; ++i)
    {
        if (operator[i] == symbol)
        {
            return 1;
        }
    }
    return 0;
}

// 判断刚扫描到的symbol是否操作数。如果symbol是操作数，返回1，否则返回0。
bool is_operand(char symbol) {
    char operand[10] = { '0','1','2','3','4','5','6','7','8','9' };
    for (int i = 0; i < 10; ++i)
    {
        if (operand[i] == symbol)
        {
            return 1;
        }
    }
    return 0;
}

// 初始化名为s的栈，初始化成功，返回0，否则返回1。
int init_stack(Stack* s) {
    (*s) = malloc(sizeof(struct stack));
    int* p = (int*)malloc(STACK_MAX_SIZE * sizeof(int));
    (*s)->base = p;
    if (!(*s)->base)//分配失败时的处理方式
        return 1;
    (*s)->top = (*s)->base;
    (*s)->number_of_elements = STACK_MAX_SIZE;
    return 0;
}

// 入栈。返回值表示是否压栈成功：0，成功；1，不成功。
int push(Stack s, char operator_or_operand) {
    if (s->top - s->base >= s->number_of_elements) {
        return 1;
    }
    else {
        *(s->top) = operator_or_operand;
        s->top++;
        return 0;
    }
}

// 出栈。返回值表示是否出栈成功：0，成功，1，不成功。
int pop(Stack s, char* p_operator_or_operand) {
    if (s->top == s->base)
        return 1;
    s->top--;
    *p_operator_or_operand = *(s->top);
    return 0;
}

// 只返回栈顶元素，通过result变量返回栈顶元素的值。函数返回值用于表示执行状态：0，成功；1，不成功。
int get_top(Stack s, char* result) {
    if (s->base == s->top) {
        return 1;
    }
    else {
        *result = *(s->top - 1);
        return 0;
    }
}

// 处理操作符。operator_on_stack_top表示操作符栈栈顶的操作符，just_scanned_operator表示从表达式里刚刚读取的操作符。返回值表示优先级：
//  -1, operator_on_stack_top 的优先级低于 just_scanned_operator；
//  0，operator_on_stack_top 的优先级等于 just_scanned_operator；
//  1，operator_on_stack_top 的优先级高于 just_scanned_operator。

int compare_operators(char operator_on_stack_top, char just_scanned_operator) {
    int i, j;
    char youxianji[][7] = {
        /*运算符之间的优先级制作成一张表格*/
        {'>', '>', '<', '<', '<', '>', '>'},
        {'>', '>', '<', '<', '<', '>', '>'},
        {'>', '>', '>', '>', '<', '>', '>'},
        {'>', '>', '>', '>', '<', '>', '>'},
        {'<', '<', '<', '<', '<', '=', '0'},
        {'>', '>', '>', '>', '0', '>', '>'},
        {'<', '<', '<', '<', '<', '0', '='}
    };
    switch (operator_on_stack_top) {
    case '+': i = 0; break;
    case '-': i = 1; break;
    case '*': i = 2; break;
    case '/': i = 3; break;
    case '(': i = 4; break;
    case ')': i = 5; break;
    case '#': i = 6; break;
    }
    switch (just_scanned_operator) {
    case '+':j = 0; break;
    case '-':j = 1; break;
    case '*':j = 2; break;
    case '/':j = 3; break;
    case '(':j = 4; break;
    case ')':j = 5; break;
    case '#':j = 6; break;
    }
    switch (youxianji[i][j]) {
    case '>':
        return 1;
    case '<':
        return -1;
    case '=':
        return 0;
    }
}
int caculate(char operator, char left_operand, char right_operand, int* result) {
    int i, j;
    switch (left_operand) {
    case'0': i = 0; break;
    case'1': i = 1; break;
    case'2': i = 2; break;
    case'3': i = 3; break;
    case'4': i = 4; break;
    case'5': i = 5; break;
    case'6': i = 6; break;
    case'7': i = 7; break;
    case'8': i = 8; break;
    case'9': i = 9; break;
    }
    switch (right_operand) {
    case'0': j = 0; break;
    case'1': j = 1; break;
    case'2': j = 2; break;
    case'3': j = 3; break;
    case'4': j = 4; break;
    case'5': j = 5; break;
    case'6': j = 6; break;
    case'7': j = 7; break;
    case'8': j = 8; break;
    case'9': j = 9; break;
    }

    switch (operator) {
    case '+':*result = i + j; break;
    case '-':*result = i - j; break;
    case '*':*result = i * j; break;
    case '/':
        if (j != 0) {
            *result = i / j;
        }
        else {
            printf("除数不能为零！\n");
            exit(0);
        }
        break;
    }
    return 0;
}

int evaluate(char* expression, int* result) {
    Stack OPTR;
    Stack OPND;
    char left_operand;
    char right_operand;
    init_stack(&OPTR);
    init_stack(&OPND);
    int char_position = 0;
    push(OPTR, expression[char_position]);
    char_position += 1;
    char top;
    char w = expression[char_position];

    while (w != '#' || top != '#')
    {
        if (is_operand(w))
        {
            push(OPND, w);
            char_position += 1;
            w = expression[char_position];
        }
        if (is_operator(w))
        {
            char c;
            get_top(OPTR, &c);
            char Total;
            int RESULT;
            switch (compare_operators(c, w)) {
            case -1:
                push(OPTR, w);
                w = expression[++char_position];
                break;
            case 0:
                pop(OPTR, &c);
                w = expression[++char_position];
                break;
            case 1:
                pop(OPND, &right_operand);
                pop(OPND, &left_operand);
                pop(OPTR, &c);
                if (c == '#' || left_operand == 0) {
                    *result = 1;
                    return *result;
                }
                else {
                    caculate(c, left_operand, right_operand, &RESULT);
                    Total = RESULT + 48;
                    push(OPND, Total);
                }
                break;
            }
        }
        get_top(OPTR, &top);
    }
    get_top(OPND, &top);
    *result = top - 48;
    return *result;
}


